using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Acme.BookStore.Domain.Entities;
using Acme.BookStore.EntityFrameworkCore;
using Acme.BookStore.Kehus;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;

namespace Acme.BookStore.EntityFrameworkCore.Kehus
{
    public class KehuRepository : EfCoreRepository<BookStoreDbContext, Kehu, string>, IKehuRepository
    {
        public KehuRepository(IDbContextProvider<BookStoreDbContext> dbContextProvider) 
            : base(dbContextProvider)
        {
        }

        public async Task<List<Kehu>> GetListAsync(
            int skipCount,
            int maxResultCount,
            string sorting,
            string filter = null)
        {
            var dbSet = await GetDbSetAsync();
            var query = dbSet.AsNoTracking();

            if (!filter.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.Name.Contains(filter));
            }

            if (sorting.Contains("Id") && !sorting.Contains("DESC"))
            {
                string lastId = null;
                if (skipCount > 0)
                {
                    var lastItems = await query
                        .OrderBy(sorting)
                        .Take(skipCount)
                        .Select(k => k.Id)
                        .ToListAsync();
                    
                    if (lastItems.Any())
                    {
                        lastId = lastItems.Last();
                    }
                }

                if (lastId != null)
                {
                    return await query
                        .Where(k => string.Compare(k.Id, lastId) > 0)
                        .OrderBy(sorting)
                        .Take(maxResultCount)
                        .ToListAsync();
                }
                else
                {
                    return await query
                        .OrderBy(sorting)
                        .Take(maxResultCount)
                        .ToListAsync();
                }
            }
            else
            {
                return await query
                    .OrderBy(sorting)
                    .Skip(skipCount)
                    .Take(maxResultCount)
                    .ToListAsync();
            }
        }

        public async Task<List<Kehu>> GetListAsync(
            int skipCount,
            int maxResultCount,
            string sorting,
            string filter = null,
            string name = null,
            string contactPerson = null,
            string phone = null,
            string mobile = null,
            string enterpriseAttribute = null)
        {
            var dbSet = await GetDbSetAsync();
            var query = dbSet.AsNoTracking();

            if (!filter.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => 
                    kehu.Name.Contains(filter) ||
                    kehu.ContactPerson.Contains(filter) ||
                    kehu.Phone.Contains(filter) ||
                    kehu.Mobile.Contains(filter));
            }

            if (!name.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.Name.Contains(name));
            }

            if (!contactPerson.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.ContactPerson.Contains(contactPerson));
            }

            if (!phone.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.Phone.Contains(phone));
            }

            if (!mobile.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.Mobile.Contains(mobile));
            }

            if (!enterpriseAttribute.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.EnterpriseAttribute.Contains(enterpriseAttribute));
            }
            
            if (sorting.Contains("Id") && !sorting.Contains("DESC"))
            {
                string lastId = null;
                if (skipCount > 0)
                {
                    var lastItems = await query
                        .OrderBy(sorting)
                        .Take(skipCount)
                        .Select(k => k.Id)
                        .ToListAsync();
                    
                    if (lastItems.Any())
                    {
                        lastId = lastItems.Last();
                    }
                }

                if (lastId != null)
                {
                    return await query
                        .Where(k => string.Compare(k.Id, lastId) > 0)
                        .OrderBy(sorting)
                        .Take(maxResultCount)
                        .ToListAsync();
                }
                else
                {
                    return await query
                        .OrderBy(sorting)
                        .Take(maxResultCount)
                        .ToListAsync();
                }
            }
            else
            {
                return await query
                    .OrderBy(sorting)
                    .Skip(skipCount)
                    .Take(maxResultCount)
                    .ToListAsync();
            }
        }
        
        public async Task<List<Kehu>> SearchByNameAsync(
            int skipCount,
            int maxResultCount,
            string sorting,
            string nameKeyword)
        {
            var dbSet = await GetDbSetAsync();
            var query = dbSet.AsNoTracking();
            
            if (!nameKeyword.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => EF.Functions.ILike(kehu.Name, $"%{nameKeyword}%"));
            }
            
            if (sorting.Contains("Id") && !sorting.Contains("DESC"))
            {
                string lastId = null;
                if (skipCount > 0)
                {
                    var lastItems = await query
                        .OrderBy(sorting)
                        .Take(skipCount)
                        .Select(k => k.Id)
                        .ToListAsync();
                    
                    if (lastItems.Any())
                    {
                        lastId = lastItems.Last();
                    }
                }

                if (lastId != null)
                {
                    return await query
                        .Where(k => string.Compare(k.Id, lastId) > 0)
                        .OrderBy(sorting)
                        .Take(maxResultCount)
                        .ToListAsync();
                }
                else
                {
                    return await query
                        .OrderBy(sorting)
                        .Take(maxResultCount)
                        .ToListAsync();
                }
            }
            else
            {
                return await query
                    .OrderBy(sorting)
                    .Skip(skipCount)
                    .Take(maxResultCount)
                    .ToListAsync();
            }
        }

        public async Task<long> GetCountAsync(string filter = null)
        {
            var dbSet = await GetDbSetAsync();
            var query = dbSet.AsNoTracking();
            
            if (!filter.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.Name.Contains(filter));
            }
            
            return await query.LongCountAsync();
        }

        public async Task<long> GetCountAsync(
            string filter = null,
            string name = null,
            string contactPerson = null,
            string phone = null,
            string mobile = null,
            string enterpriseAttribute = null)
        {
            var dbSet = await GetDbSetAsync();
            var query = dbSet.AsNoTracking();

            if (!filter.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => 
                    kehu.Name.Contains(filter) ||
                    kehu.ContactPerson.Contains(filter) ||
                    kehu.Phone.Contains(filter) ||
                    kehu.Mobile.Contains(filter));
            }

            if (!name.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.Name.Contains(name));
            }

            if (!contactPerson.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.ContactPerson.Contains(contactPerson));
            }

            if (!phone.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.Phone.Contains(phone));
            }

            if (!mobile.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.Mobile.Contains(mobile));
            }

            if (!enterpriseAttribute.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => kehu.EnterpriseAttribute.Contains(enterpriseAttribute));
            }
            
            return await query.LongCountAsync();
        }
        
        public async Task<long> GetCountByNameAsync(string nameKeyword)
        {
            var dbSet = await GetDbSetAsync();
            var query = dbSet.AsNoTracking();
            
            if (!nameKeyword.IsNullOrWhiteSpace())
            {
                query = query.Where(kehu => EF.Functions.ILike(kehu.Name, $"%{nameKeyword}%"));
            }
            
            return await query.LongCountAsync();
        }
    }
} 